#include "AudioManager.h"
using namespace AudioManager;
Manager::Manager(int maxChannel)
{
    nbClips=0;
	result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->getVersion(&version);
    ERRCHECK(result);
    if (version < FMOD_VERSION)
    {
        printf("Error!  You are using an old version of FMOD %08x.  This program requires %08x\n", version, FMOD_VERSION);
        exit(-1);
    }
	ERRCHECK(result);
	result = system->init(maxChannel, FMOD_INIT_NORMAL, 0);
    ERRCHECK(result);

	Track *MasterTrack = new Track(system);
	FMOD::ChannelGroup *master;
	ERRCHECK(system->createChannelGroup("Master", &master));
	MasterTrack->setOutputChannel(master);

	tracks.push_back(MasterTrack);
	currentPosition=0;
	for(int i=0;i<9;i++){
		tracks.push_back( new Track(system));
	}
}


int Manager::addTrack(Track * track)
{
	tracks.push_back(track);
	return 0;
}

int Manager::addTrack()
{
	Track *t = new Track(system);
	tracks.push_back(t);
	return 0;
}

int Manager::rmTrack(unsigned int id)
{
	if(tracks.size()>id)
		tracks.erase(tracks.begin()+id);
	return 0;
}

int Manager::rmTrack(Track * track)
{
	for(unsigned int i=0;i<tracks.size();i++)
	{
		if(tracks.at(i)==track)
		{
			tracks.erase(tracks.begin()+i);
		}
	}
	return 0;
}

 int Manager::addClip(char *path)
 {
	 if(path!=NULL)
	 {
		AudioClip * clip = new AudioClip(path,*system);
		 clips.push_back(clip);
		return 0;
	 }
	 return -1;
 }
 int Manager::setClip(int clipID,int row,int column)
 {
	 if(clipID==-1)
		 return 0;
	 tracks.at(column)->addClip(clips.at(clipID),0,0,0,0,row);
	 return 0;
 }
  int Manager::addClip(AudioClip * clip,int row,int column)
 {
	tracks.at(column)->addClip(clip,0,0,0,0,row);
	return 0;
 }

 int Manager::rmClip(unsigned int clipID)
 {
	 if(clips.size()>clipID){
		clips.erase(clips.begin()+clipID);
	 }

	 return 0;
 }
 int Manager::rmClip(AudioClip *clip)
 {
	 //clips.
	 return 0;
 }
 vector<char *> Manager::getClipsInfos()
 {
	vector<char *> filesName;
	for(unsigned int i=0;i<clips.size();i++)
	{
		char * name = clips[i]->getName();
        filesName.push_back(name);
	}
	return filesName;
 }

float Manager::getTrackDB(int track_id,int side)
{
	float *f=new float[512];
	tracks.at(track_id)->getOutputChannel()->getSpectrum(f,512,side,FMOD_DSP_FFT_WINDOW_RECT);
	float max=0;
	for(int i=0;i<512;i++)
	{
		if(max<f[i])
			max=f[i];
	}
    if (max < 0.0000000001) { return -200.0; } 
    return (float)(20.0 * log10(max));
}

 void Manager::ERRCHECK(FMOD_RESULT result)
{
    if (result != FMOD_OK)
    {
        printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
		std::system("PAUSE");
        exit(-1);
    }
}

void Manager::play(int row)
{
	for(int i=1;i<=8;i++){
		Track *t = tracks.at(i);
		if(t->getClips()[row].clip!=NULL){
			if(t->isPlaying(row)){
				t->stopChannel(row);
			}
			FMOD::Channel *chan=NULL;
			FMOD_RESULT result =system->playSound(FMOD_CHANNEL_FREE,t->getClips()[row].clip->getSound(),false,&chan);
			t->getClips()[row].channel=chan;
			if(AudioUtils::ERRCHECK(result)){
				t->getClips()[row].channel->setChannelGroup(tracks.at(row)->getOutputChannel());
				tracks.at(0)->getOutputChannel()->addGroup(t->getOutputChannel());
			}
		}
	}
}
void Manager::play(int row,int column)
{
	Track *t = tracks.at(column);
	if(t->getClips()[row].clip!=NULL){
		if(t->isPlaying(row)){
			t->stopChannel(row);
		}
		else{
			FMOD::Channel *chan=NULL;
			FMOD_RESULT result =system->playSound(FMOD_CHANNEL_REUSE,t->getClips()[row].clip->getSound(),false,&chan);
			t->getClips()[row].channel=chan;
			if(AudioUtils::ERRCHECK(result)){
				t->getClips()[row].channel->setChannelGroup(tracks.at(column)->getOutputChannel());
				tracks.at(0)->getOutputChannel()->addGroup(t->getOutputChannel());
			}
		}
	}
}

Track * Manager::getTrack(int track_id){
	return tracks.at(track_id);
}

FMOD::DSP * Manager::getTrackDSP(FMOD_DSP_TYPE dspIndex, int track_ID){
	Track * t = getTrack(track_ID);
	return t->getDSP(dspIndex);
}


void Manager::setMuteOnTrack(int trackID){
	if(!getTrack(trackID)->isMute())
		getTrack(trackID)->setMute();
	else
		getTrack(trackID)->setUnMute();
}
void Manager::setListenOnTrack(int trackID,bool listen){
}
void Manager::setSoloOnTrack(int trackID){
	if(tracks.at(trackID)->isSolo())
		tracks.at(trackID)->setUnSolo();
	else
		tracks.at(trackID)->setSolo();

	for(int i=1;i<9;i++){
		if(!tracks.at(i)->isSolo()){
			if(i!=trackID)
				tracks.at(i)->setMute();
		}
		else{
			if(trackID!=i){
				tracks.at(i)->setUnMute();
			}
		}
	}		
}
void Manager::setRecOnTrack(int trackID){
	getTrack(trackID)->setRec(!getTrack(trackID)->isRecording());
	if(getTrack(trackID)->isRecording()){
		for(int i=1;i<9;i++){
			if(trackID!=i){
				getTrack(trackID)->setRec(false);
			}
		}
	}
}

void Manager::pause(){
}
void Manager::resume(){
}
void Manager::stop(){
}
void Manager::begin(){
}
void Manager::end(){
}
void Manager::setPanTrack(int trackID,float pan){
	tracks.at(trackID)->setPan(pan);
}
void Manager::setGainTrack(int trackID,float gain){
	tracks.at(trackID)->setGain(gain);
}

int Manager::getCurrentPosition()
{
	return currentPosition;
}

void loadTrack(){

}

void Manager::comp_setAtck(int trackID,int value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_COMPRESSOR);
	dsp->setParameter(FMOD_DSP_COMPRESSOR_ATTACK,(float)value);
}
void Manager::comp_setRelease(int trackID,int value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_COMPRESSOR);
	dsp->setParameter(FMOD_DSP_COMPRESSOR_RELEASE,(float)value);
}
void Manager::comp_setThreshold(int trackID,int value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_COMPRESSOR);
	dsp->setParameter(FMOD_DSP_COMPRESSOR_THRESHOLD,(float)value);
}
void Manager::comp_setGain(int trackID,int value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_COMPRESSOR);
	dsp->setParameter(FMOD_DSP_COMPRESSOR_GAINMAKEUP,(float)value);
}
void Manager::comp_setActive(int trackID){
	bool b=true;
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_COMPRESSOR);
	dsp->getBypass(&b);
	dsp->setBypass(!b);
}
void Manager::comp_isActive(int trackID,bool *b){
	tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_COMPRESSOR)->getBypass(b);
}

void Manager::chorus_isActive(int trackID,bool *b){
	tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS)->getBypass(b);
}
void Manager::chorus_setActive(int trackID)
{
	bool b=true;
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->getBypass(&b);
	dsp->setBypass(!b);
}
void Manager::chorus_setDelay(int trackID,float value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->setParameter(FMOD_DSP_CHORUS_DELAY,value);
}
void Manager::chorus_setDepth(int trackID,float value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->setParameter(FMOD_DSP_CHORUS_DEPTH,value);
}
void Manager::chorus_setDryMix(int trackID,float value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->setParameter(FMOD_DSP_CHORUS_DRYMIX,value);
}
void Manager::chorus_setRate(int trackID,float value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->setParameter(FMOD_DSP_CHORUS_RATE,value);
}
void Manager::chorus_setWetMix1(int trackID,float value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->setParameter(FMOD_DSP_CHORUS_WETMIX1,value);
}
void Manager::chorus_setWetMix2(int trackID,float value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->setParameter(FMOD_DSP_CHORUS_WETMIX2,value);
}
void Manager::chorus_setWetMix3(int trackID,float value){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	dsp->setParameter(FMOD_DSP_CHORUS_WETMIX3,value);
}

void Manager::disto_setActive(int trackID){
	bool b=true;
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_DISTORTION);
	dsp->getBypass(&b);
	dsp->setBypass(!b);
}
void Manager::disto_setDistoLVL(int trackID,float lvl){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_DISTORTION);
	dsp->setParameter(FMOD_DSP_DISTORTION_LEVEL,lvl);
}

void Manager::getPluginsValues(int trackID, float * values){
	FMOD::DSP *dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_COMPRESSOR);
	char *s;
	s=new char[16];
	dsp->getParameter(FMOD_DSP_COMPRESSOR_ATTACK,&values[0],s,16);
	dsp->getParameter(FMOD_DSP_COMPRESSOR_GAINMAKEUP,&values[1],s,16);
	dsp->getParameter(FMOD_DSP_COMPRESSOR_RELEASE,&values[2],s,16);
	dsp->getParameter(FMOD_DSP_COMPRESSOR_THRESHOLD,&values[3],s,16);

	/*dsp=tracks.at(trackID)->getDSP(FMOD_DSP_TYPE_CHORUS);
	char *s;
	s=new char[16];
	dsp->getParameter(FMOD_DSP_CHORUS_DELAY,&values[4],s,16);
	dsp->getParameter(FMOD_DSP_CHORUS_DEPTH,&values[5],s,16);
	dsp->getParameter(FMOD_DSP_CHORUS_DRYMIX,&values[6],s,16);
	dsp->getParameter(FMOD_DSP_CHORUS_RATE,&values[7],s,16);*/
}



float * Manager::getSpectrum(int trackID){
	float * spectrum = new float [512];
	tracks.at(trackID)->getOutputChannel()->getSpectrum(spectrum,512,0,FMOD_DSP_FFT_WINDOW_BLACKMAN);
	int ctr = 0;
    int FreqPerBand =  512 / 16;
	float *spectrumArray=new float[16];
    for (int i = 0; i < 16; i++)
    {
        spectrumArray[i] = 0.0f;
        for (int j = 0; j < FreqPerBand; j++)
        {
            spectrumArray[i] += pow(spectrum[ctr++], 2);
        }
        spectrumArray[i] = sqrt(spectrumArray[i]/FreqPerBand); // Get the root-mean-square of the values.
        spectrumArray[i] =(float)( 10 * log10(spectrumArray[i]/pow(10.0, -12))); // Turn the values into decibels.
    }
	return spectrum;
}

bool Manager::isPlaying(int trackID,int clipIndex){
	Track * track = this->getTrack(trackID);
	return track->isPlaying(clipIndex);
}
void Manager::stopChannel(int trackID,int clipIndex){
	Track *track = getTrack(trackID);
	return track->stopChannel(clipIndex);
}

int Manager::getNbClips(){
	return clips.size();
}

void Manager::stopAll(){
	tracks.at(0)->getOutputChannel()->stop();
}

bool Manager::isAssign(int trackID,int clipID){
	return tracks.at(trackID)->isAssign(clipID);
}
void Manager::rec(){

	FMOD_CREATESOUNDEXINFO exinfo;
	exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO);
    exinfo.numchannels      = 1;
    exinfo.format           = FMOD_SOUND_FORMAT_PCM16;
    exinfo.defaultfrequency = RECORDRATE;
    exinfo.length           = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 30;

	result = system->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_LOOP_NORMAL | FMOD_OPENUSER, &exinfo, &recordedSound);

	result = system->recordStart(0, recordedSound, true);
    ERRCHECK(result);
	
	//tracks[0]->getOutputChannel()->getChannel(0,)

}
